iT邦幫忙

1

STM32-19 CAN-BUS (下)

  • 分享至 

  • xImage
  •  

結構體介紹

  • CAN_FilterTypeDef
typedef struct
{
  uint32_t FilterIdHigh;        
  uint32_t FilterIdLow;          
  uint32_t FilterMaskIdHigh;      
  uint32_t FilterMaskIdLow;      
  uint32_t FilterFIFOAssignment;  
  uint32_t FilterBank;           
  uint32_t FilterMode;           
  uint32_t FilterScale;          
  uint32_t FilterActivation;     
  uint32_t SlaveStartFilterBank;  
} CAN_FilterTypeDef;

FilterIdHigh : 16bit 用來放STDID

FilterIdLow : 16 bit 用來放EXTID

FilterMaskIdHigh : 依模式選擇 Mask 1 需比對 0不比對 LIST模式下設置第二組ID

FilterMaskIdLow : 依模式選擇 Mask 1 需比對 0不比對 LIST模式下設置第二組ID

FilterFIFOAssignment : 選擇相關聯的FIFO編號 假設使用RX0 就填入 CAN_RX_FIFO0

FilterBank : 濾波器編組 根據板子不同可分為 0-13 or 0-27 (我這塊板子只有14個也就是0-13)

FilterMode : Filter模式選擇 有兩種 LIST 跟MASK

FilterScale : 選擇Filter位寬 分為16與32bit (CAN_FILTERSCALE_32BIT , CAN_FILTERSCALE_16BIT)

FilterActivation : 啟用Filter (CAN_FILTER_ENABLE)

SlaveStartFilterBank : 只有在雙CAN的板子上有用

  • CAN_TxHeaderTypeDef
typedef struct
{
  uint32_t StdId;    
  uint32_t ExtId;    
  uint32_t IDE;      
  uint32_t RTR;      
  uint32_t DLC;     
  FunctionalState TransmitGlobalTime;
} CAN_TxHeaderTypeDef;

StdId : 標準模式ID (11 bit)

ExtId : 擴展模式ID (32 bit)

IDE : 表示是擴展還標準(CAN_ID_STD , CAN_ID_EXT)

RTR : 表示是資料訊息還是遠端請求 (CAN_RTR_DATA , CAN_RTR_REMOTE)

DLC : 表示傳送資料長度 0-8 bytes

TransmitGlobalTime : 指定是否在傳輸開始時捕獲時間戳計數器當中的值,透過DATA6 和 DATA7發送,也就是會替換 pData[6] 和 pData[7]。(ENABLE , DISABLE) 需要開啟時間捕獲模式

  • CAN_RxHeaderTypeDef
typedef struct
{
  uint32_t StdId;   
  uint32_t ExtId;   
  uint32_t IDE;    
  uint32_t RTR;      
  uint32_t DLC;      
  uint32_t Timestamp; 
  uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;

StdId : 標準模式ID (11 bit)

ExtId : 擴展模式ID (32 bit)

IDE : 表示是擴展還標準(CAN_ID_STD , CAN_ID_EXT)

RTR : 表示是資料訊息還是遠端請求 (CAN_RTR_DATA , CAN_RTR_REMOTE)

DLC : 表示傳送資料長度 0-8 bytes

Timestamp : 指定在訊息接收開始時捕獲的時間戳計數器當中的值。 需要開啟時間捕獲模式

FilterMatchIndex : 指定配對哪一個Filter元素的Index


Filter設定說明

只有在CAN接收時會需要設置到Filter

接著來看看手冊當中的Filter說明
https://ithelp.ithome.com.tw/upload/images/20220327/20146325HKl44iHRqy.png
這一段說明的其實就是CAN2.0A與CAN2.0B的Arbitration Field

  • 一個32bit的Filter,可以看到在CAN2.0B當中STDID的確有10個bit,EXTID有17個bit而剩餘的就是IDE與RTR共 32bit,所以32位元的可以實現對標準與擴展的訊息過濾
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325zKyc47Vb0o.png
  • 兩個16bit的Filter,包含了CAN2.0A當中的11個STDID、1個IDE、1個RTR與3個EXTID,只能實現對標準模式的訊息過濾。
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325CtOtqSEOxz.png

Filter模式

  • IDMASK : 當設置為1則會去比對所接收到的ID與Register當中的ID相不相符,0則不比對。像下方這張圖來說紅色的部分就是會比對的ID位置必須與暫存器當中相同才可以通過。
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325UB39qM9Dvu.png
    以32bit來看最多只能寫入一組ID去過濾而已
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325qLtlsPXpHw.png
    以16bit來看最多可寫入兩組ID,但只能識別標準模式下的ID
    https://ithelp.ithome.com.tw/upload/images/20220327/2014632523jjYgbMy7.png
  • IDLIST : 所接收到的訊息當中ID必須與Filter Register當中所有的bit相同才會接收,只要有任何一個不相同則不接收
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325eyPkKBvCr2.png
    以32位元來看因為是IDLIST模式,可以設置兩種ID來進行過濾
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325iT2AL6FvNN.png
    以16位元來看最多可設置四種ID來進行過濾
    https://ithelp.ithome.com.tw/upload/images/20220327/20146325qIouE0rlDA.png

程式碼範例

全域變數宣告

uint8_t send_data[8] = {0,1,2,3,4,5,6,7}; //傳送的資料
uint8_t rece_data[8]; //接收的Buffer 
CAN_TxHeaderTypeDef TxHeader; 
CAN_RxHeaderTypeDef RxHeader;
uint32_t TxMailBox;

使用RX中斷去接收訊息

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &RxHeader, rece_data);
}
  • CAN2.0A 標準模式且Filter選為Mask
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
	TxHeader.DLC =8;
  TxHeader.ExtId = 0;
  TxHeader.IDE = CAN_ID_STD;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.StdId = 0x105;
  TxHeader.TransmitGlobalTime = DISABLE;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = 0x105<<5;
	CAN1Filter.FilterIdLow = 0x0000;
	CAN1Filter.FilterMaskIdHigh = 0x1111;
	CAN1Filter.FilterMaskIdLow = 0x1111;
	CAN1Filter.SlaveStartFilterBank = 0;

	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325jag8SQOFoD.png
經過邏輯分析儀後測試ID為105,這邊是將Filter設定為Mask模式,且將MASKID都設置為1需要檢驗所接收到了ID是否與暫存器中ID相同。

  • CAN2.0A 標準模式且Filter選為IDLIST
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<2 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0;
	  TxHeader.IDE = CAN_ID_STD;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.StdId = 0x103+x;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = 0x103<<5;  //第一組可通過的ID
	CAN1Filter.FilterIdLow = 0x0000;
	CAN1Filter.FilterMaskIdHigh = 0x104<<5; //第二組可通過的ID
	CAN1Filter.FilterMaskIdLow = 0x0000;
	CAN1Filter.SlaveStartFilterBank = 0;
}

https://ithelp.ithome.com.tw/upload/images/20220327/201463251VTKYoBRu3.png
可以看到使用邏輯分析儀後的測試結果,在ID為103與104時可通過Filter成功接收回來。

上方左移五位的原因是為了對齊32bit的高位,STDID為11位需要左移才能對齊。

  • CAN2.0B 擴展模式且Filter選為Mask
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  TxHeader.DLC =8;
  TxHeader.IDE = CAN_ID_EXT;
  TxHeader.RTR = CAN_RTR_DATA;
  TxHeader.ExtId = 0x1234ABCD;
  TxHeader.TransmitGlobalTime = DISABLE;
  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDMASK;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterMaskIdHigh = 0;
	CAN1Filter.FilterMaskIdLow = 0;
	CAN1Filter.SlaveStartFilterBank = 0;
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325brNZ10mZVl.png

  • CAN2.0B 擴展模式且Filter選為IDLIST
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<2 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0x1234ABCD+x;
	  TxHeader.IDE = CAN_ID_EXT;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCE<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.SlaveStartFilterBank = 0;
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325GJWwubqh7Y.png
上圖可以看到對應的ID為0x1234ABCD與0x1234ABCE,Filter為LIST模式而32位寬的Filter當中可以設置兩組EXTID來過濾。

  • 當有好幾組需要通過Filter時
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_CAN1_Init();
  /* USER CODE BEGIN 2 */
  ConfigFliter();
  HAL_CAN_Start(&hcan1);
  HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
  for(int x = 0 ; x<4 ;x++)
  {
	  TxHeader.DLC =8;
	  TxHeader.ExtId = 0x1234ABCD+x;
	  TxHeader.IDE = CAN_ID_EXT;
	  TxHeader.RTR = CAN_RTR_DATA;
	  TxHeader.TransmitGlobalTime = DISABLE;
	  HAL_CAN_AddTxMessage(&hcan1, &TxHeader, send_data, &TxMailBox);
	  HAL_Delay(100);
  }
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}
void ConfigFliter(void)
{
	CAN_FilterTypeDef CAN1Filter;
	CAN1Filter.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter.FilterBank = 0;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCD<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCE<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.SlaveStartFilterBank = 0;

	CAN_FilterTypeDef CAN1Filter1;
	CAN1Filter1.FilterActivation = CAN_FILTER_ENABLE;
	CAN1Filter1.FilterFIFOAssignment = CAN_RX_FIFO0;
	CAN1Filter1.FilterMode = CAN_FILTERMODE_IDLIST;
	CAN1Filter1.FilterScale = CAN_FILTERSCALE_32BIT;
	CAN1Filter1.FilterBank = 1;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABCF<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter.FilterIdHigh = ((0x1234ABCD<<3)>>16) & 0xffff;
	CAN1Filter.FilterIdLow =((0x1234ABD0<<3)& 0xffff) | CAN_ID_EXT;
	CAN1Filter1.SlaveStartFilterBank = 0;

	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter);
	HAL_CAN_ConfigFilter(&hcan1, &CAN1Filter1);
}

https://ithelp.ithome.com.tw/upload/images/20220327/20146325V9gQop4fTn.png
當有好幾組需要設置的時候,這時候就可以使用編組來設置其餘的過濾器ID,這邊設置了編組0與編組1的ID。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言